package checker

import (
	"fmt"
	"strings"
	"kumachan/interpreter/lang/ast"
	"kumachan/interpreter/lang/common/name"
	"kumachan/interpreter/lang/common/attr"
	"kumachan/interpreter/lang/common/source"
	"kumachan/interpreter/compiler/checker/typsys"
)


func (reg *FunctionRegistry) InjectFunction(f *Function) {
	var n = f.Name.Name
	{ var reg = *reg
	var existing, exists = reg[n]
	if exists {
		reg[n] = append(existing, f)
	} else {
		reg[n] = [] *Function { f }
	} }
}

func craftFunction (
	f_name    name.FunctionName,
	kind      ast.FuncKind,
	exported  bool,
	loc       source.Location,
	sig       FunctionSignature,
	body      FunctionBody,
) *Function {
	return &Function {
		FunctionAttrs: attr.FunctionAttrs {
			Attrs: attr.Attrs {
				Location: loc,
			},
			Generated: true,
		},
		AstNode: &ast.DeclFunction {
			Node: ast.NodeFromLocation(loc),
			Kind: kind,
		},
		Exported:  exported,
		Name:      f_name,
		Signature: sig,
		Body:      body,
	}
}

func describeFunctionSignature(sig FunctionSignature) string {
	var param_desc_list = make([] string, len(sig.TypeParameters))
	for i, p := range sig.TypeParameters {
		param_desc_list[i] = (func() string {
			if p.Bound.Kind != typsys.NullBound {
				var kind_desc = (func() string {
					switch p.Bound.Kind {
					case typsys.SupBound, typsys.OpenTopBound:
						return "<"
					case typsys.InfBound, typsys.OpenBottomBound:
						return ">"
					default:
						panic("impossible branch")
					}
				})()
				var val_desc = typsys.DescribeType(p.Bound.Value, nil)
				return fmt.Sprintf("%s %s %s", p.Name, kind_desc, val_desc)
			} else {
				return p.Name
			}
		})()
	}
	var params_desc = (func() string {
		if len(param_desc_list) > 0 {
			return fmt.Sprintf("[%s] ", strings.Join(param_desc_list, ", "))
		} else {
			return ""
		}
	})()
	var implicit_desc = (func() string {
		if len(sig.ImplicitContext.Fields) > 0 {
			var implicit_t = &typsys.NestedType {
				Content: sig.ImplicitContext,
			}
			return fmt.Sprintf("%s ", typsys.DescribeType(implicit_t, nil))
		} else {
			return ""
		}
	})()
	var io_t = &typsys.NestedType {
		Content: sig.InputOutput,
	}
	var io_desc = typsys.DescribeType(io_t, nil)
	return fmt.Sprintf("%s%s%s", params_desc, implicit_desc, io_desc)
}


